package com.mxl.datebase.orm;

import java.io.Serializable;
import java.lang.reflect.Type;
import java.math.BigDecimal;
import java.util.Collection;
import java.util.Iterator;
import java.util.List;
import java.util.Map;

import org.hibernate.criterion.Criterion;
import org.hibernate.criterion.Order;
import org.hibernate.criterion.Projection;

import com.mxl.datebase.orm.pagination.Page;


/**
 * ORM中基本的增、删、改和查操作.
 * 
 * 复杂查询请使用QueryDao接口，大数据量的批量处理请使用BatchDao接口.
 * 
 * 用户自定义的Dao接口如需要向service层提供BaseDao中定义的方法，可以继承该接口，例如：
 *  <pre>
 *  public interface CategoryDao extends BaseDao&lt;Category, String&gt; {
 *  	//TODO: add other method for service level use
 *  }
 *  </pre>
 * 其实现类可以定义如下：
 *  <pre>
 *  public class CategoryDaoImpl extends BaseDaoSupport&lt;Category, String&gt; implements CategoryDao{
 *  
 *  }
 *  </pre>
 * 用户自定义的Dao接口如无需向service层提供BaseDao中定义的方法，可以不必继承该接口，例如：<br>
 *  <pre>
 *  public interface CategoryDao{
 *  	//TODO: add other method for service level use
 *  }
 *  </pre>
 * 其实现类可以定义如下：<br>
 *  <pre>
 *  public class CategoryDaoImpl extends BaseDaoSupport&lt;Category, String&gt; implements CategoryDao{
 *  	
 *  }
 *  </pre>
 * 对于采用HQL的查询方式，建议所有的查询语句定义成private final String的方式放在实现类的前面，例如：<br>
 *  <pre>
 *  public class CategoryDaoImpl extends BaseDaoSupport&lt;Category, String&gt; implements CategoryDao{
 *  
 *  	private final String FIND_CATEGORY_BY_DESCN = "from Category c where c.descn like ?";
 *  
 *  	...someMethod(...) {
 *  		findCategoryByDescn(FIND_CATEGORY_BY_DESCN, new Object[]{"%abc%"});
 *  	}
 *  }
 *  </pre>
 * 对于动态条件的查询，不建议使用字符串拼接HQL的方式实现，推荐采集Criteria的方式.
 *
 *
 * @param <T> 实体类
 * @param <PK> 实体类的主键类型
 * 
 
 */
public interface BaseDao<T, PK extends Serializable> {
	
	public Type getModelType();

	/**
	 * 保存新增或修改的对象.
	 * 
	 * @param entity
	 * @return
	 */
	public T save(final T entity);
	
	/**
	 * 更新对象
	 * 
	 * @param entity
	 */
	public T update(final T entity);
	
	/**
	 * 合并session中的对象并保存到数据库
	 * 
	 * @param entity
	 * @return
	 */
	public T merge(final T entity);

	/**
	 * 删除对象.
	 * 
	 * @param entity 对象必须是session中的对象或含id属性的transient对象.
	 */
	public void delete(final T entity);

	/**
	 * 按id删除对象.
	 */
	public void delete(final PK id);

	/**
	 * 按id获取对象，如果是复合主键，应该参照composite-id的方式创建主键对象.
	 */
	public T get(final PK id);
	
	/**
	 * 按id列表获取对象列表.
	 */
	public List<T> get(final Collection<PK> ids);
	
	/**
	 * 获取被数据库锁锁住的对象
	 * 
	 * @param id
	 * @return
	 */
	public T getForUpdate(final PK id);
	
	/**
	 * 刷新对象
	 * 
	 * @param object
	 * @return
	 */
	public T refresh(T entity);
	
	/**
	 *	获取全部对象.
	 */
	public List<T> getAll();
	
	/**
	 * 从session中清除此对象，使之成为游离状态
	 * 
	 * @param entity
	 */
	public void evict(T entity);
	
	/**
	 * 分页获取对象
	 * 
	 * @param page
	 * @return
	 */
	public List<T> getAll(Page page);

	/**
	 *	获取全部对象, 支持按属性行序.
	 */
	public List<T> getAll(String orderByProperty, boolean isAsc);

	/**
	 * 按属性查找对象列表, 匹配方式为相等.
	 */
	public List<T> findBy(final String propertyName, final Object value);

	/**
	 * 按属性查找唯一对象, 匹配方式为相等.如果结果不唯一，取第一条记录.
	 */
	public T findUniqueBy(final String propertyName, final Object value);

	/**
	 * 按HQL查询对象列表，一次查出所有数据，查询速度比对应的iterator方法高，但对于大数据量要求内存多.
	 * <pre>
	 * 根据hql中的查询表达式，返回的X对象可以是以下几种：Entity对象、Object[]、List或Map
	 * 比如：
	 * <li>String hql = "from Category c";</li>则返回Entity对象c
	 * <li>String hql = "select c.categoryId, c.name, c.description from Category c";</li>则返回Object[]
	 * <li>String hql = "select new List(c.categoryId, c.name, c.description) from Category c";</li>则返回List
	 * <li>String hql = "select new Map(c.categoryId as id, c.name as name, c.description as descn) from Category c";</li>则返回Map
	 * </pre>
	 * @param hql
	 * @param values 数量可变的参数,按顺序绑定.
	 * @see #iterator(String, Object...)
	 */
	public <X> List<X> find(final String hql, final Object... values);
	
	/**
	 * 按HQL查询返回对象迭代器，查询会发出N+1次查询，注意与对应find方法区分，当数据量较大时使用此方法.
	 * 注意：此方法必需在事务环境中执行，否则会执行失败.
	 * <pre>
	 * 根据hql中的查询表达式，返回的X对象可以是以下几种：Entity对象、Object[]、List或Map
	 * 比如：
	 * <li>String hql = "from Category c";</li>则返回Entity对象c
	 * <li>String hql = "select c.categoryId, c.name, c.description from Category c";</li>则返回Object[]
	 * <li>String hql = "select new List(c.categoryId, c.name, c.description) from Category c";</li>则返回List
	 * <li>String hql = "select new Map(c.categoryId as id, c.name as name, c.description as descn) from Category c";</li>则返回Map
	 * </pre>
	 * @param hql
	 * @param values 数量可变的参数,按顺序绑定.
	 * @see #find(String, Object...)
	 */
	public <X> Iterator<X> iterator(final String hql, final Object... values);
	
	/**
	 * 按HQL分页查询对象列表.
	 * <pre>
	 * 根据hql中的查询表达式，返回的X对象可以是以下几种：Entity对象、Object[]、List或Map
	 * 比如：
	 * <li>String hql = "from Category c";</li>则返回Entity对象c
	 * <li>String hql = "select c.categoryId, c.name, c.description from Category c";</li>则返回Object[]
	 * <li>String hql = "select new List(c.categoryId, c.name, c.description) from Category c";</li>则返回List
	 * <li>String hql = "select new Map(c.categoryId as id, c.name as name, c.description as descn) from Category c";</li>则返回Map
	 * </pre>
	 * @param values 数量可变的参数,按顺序绑定.
	 */
	public <X> List<X> find(final String hql, Page page, final Object... values);

	/**
	 * 按HQL查询对象列表.
	 * <pre>
	 * 根据hql中的查询表达式，返回的X对象可以是以下几种：Entity对象、Object[]、List或Map
	 * 比如：
	 * <li>String hql = "from Category c";</li>则返回Entity对象c
	 * <li>String hql = "select c.categoryId, c.name, c.description from Category c";</li>则返回Object[]
	 * <li>String hql = "select new List(c.categoryId, c.name, c.description) from Category c";</li>则返回List
	 * <li>String hql = "select new Map(c.categoryId as id, c.name as name, c.description as descn) from Category c";</li>则返回Map
	 * </pre>
	 * @param hql
	 * @param values 命名参数,按名称绑定.
	 * @see #iterator(String, Map)
	 */
	public <X> List<X> find(final String hql, final Map<String, ?> values);
	
	/**
	 * 按HQL查询返回对象迭代器，查询会发出N+1次查询，注意与对应find方法区分，当数据量较大时使用此方法.
	 * 注意：此方法必需在事务环境中执行，否则会执行失败.
	 * <pre>
	 * 根据hql中的查询表达式，返回的X对象可以是以下几种：Entity对象、Object[]、List或Map
	 * 比如：
	 * <li>String hql = "from Category c";</li>则返回Entity对象c
	 * <li>String hql = "select c.categoryId, c.name, c.description from Category c";</li>则返回Object[]
	 * <li>String hql = "select new List(c.categoryId, c.name, c.description) from Category c";</li>则返回List
	 * <li>String hql = "select new Map(c.categoryId as id, c.name as name, c.description as descn) from Category c";</li>则返回Map
	 * </pre>
	 * @param hql
	 * @param values 数量可变的参数,按顺序绑定.
	 */
	public <X> Iterator<X> iterator(final String hql, final Map<String, ?> values);
	
	/**
	 * 按HQL分页查询对象列表.
	 * <pre>
	 * 根据hql中的查询表达式，返回的X对象可以是以下几种：Entity对象、Object[]、List或Map
	 * 比如：
	 * <li>String hql = "from Category c";</li>则返回Entity对象c
	 * <li>String hql = "select c.categoryId, c.name, c.description from Category c";</li>则返回Object[]
	 * <li>String hql = "select new List(c.categoryId, c.name, c.description) from Category c";</li>则返回List
	 * <li>String hql = "select new Map(c.categoryId as id, c.name as name, c.description as descn) from Category c";</li>则返回Map
	 * </pre>
	 * @param hql
	 * @param page
	 * @param values 命名参数,按名称绑定.
	 */
	public <X> List<X> find(final String hql, Page page, final Map<String, ?> values);

	/**
	 * 按HQL查询唯一对象，如果结果不唯一，取第一条记录.
	 * 
	 * @param values 数量可变的参数,按顺序绑定.
	 */
	public <X> X findUnique(final String hql, final Object... values);

	/**
	 * 按HQL查询唯一对象，如果结果不唯一，取第一条记录.
	 * 
	 * @param values 命名参数,按名称绑定.
	 */
	public <X> X findUnique(final String hql, final Map<String, ?> values);

	/**
	 * 按Criteria查询对象列表.
	 * 
	 * @param criterions 数量可变的Criterion.
	 * @return
	 * @see org.hibernate.criterion.Restrictions
	 */
	public List<T> find(final Criterion... criterions);
	
	/**
	 * 按Criteria查询对象有序列表.
	 * 
	 * @param orders
	 * @param criterions 数量可变的Criterion.
	 * @return
	 * @see org.hibernate.criterion.Restrictions
	 * @see org.hibernate.criterion.Order
	 */
	public List<T> find(final Order[] orders, final Criterion... criterions);
	
	/**
	 * 按Criteria投影查询
	 * 
	 * @param <X>
	 * @param projections
	 * @param criterions
	 * @return
	 * @see org.hibernate.criterion.Projections 
	 * @see org.hibernate.criterion.Property#forName(String)
	 */
	public <X> List<X> find(final List<Projection> projections, final Criterion... criterions);
	
	/**
	 * 投影查询
	 * 
	 * @param <X>
	 * @param projections
	 * @param orders
	 * @param criterions
	 * @return
	 * @see org.hibernate.criterion.Projections
	 */
	public <X> List<X> find(final List<Projection> projections, final Order[] orders, final Criterion...criterions);
	
	/**
	 * 按Criteria分页查询对象列表.
	 * 
	 * @param page
	 * @param criterions 数量可变的Criterion.
	 * @return
	 * @see org.hibernate.criterion.Restrictions
	 */
	public List<T> find(Page page, final Criterion...criterions);
	
	/**
	 * 按Criteria分页查询对象列表，并排序.
	 * @param page 分页对象
	 * @param orders Order.asc(beanProperty)或者Order.desc(beanProperty)
	 * @param criterions
	 * @return
	 * @see org.hibernate.criterion.Restrictions
	 * @see org.hibernate.criterion.Order
	 */
	public List<T> find(Page page, final Order[] orders, final Criterion...criterions);
	
	/**
	 * 按Criteria分页投影查询，并排序.
	 * @param <X>
	 * @param projections
	 * @param page
	 * @param orders
	 * @param criterions
	 * @return
	 */
	public <X> List<X> find(final List<Projection> projections, Page page, final Order[] orders, final Criterion...criterions);

	/**
	 * 按Criteria查询唯一对象，如果结果不唯一，取第一条记录.
	 * 
	 * @param criterions 数量可变的Criterion.
	 */
	public T findUnique(final Criterion... criterions);
	
	/**
	 * 返回指定属性的求和结果
	 * 
	 * @param <X>
	 * @param propertyName 要求求和的属性名称
	 * @param criterions 限定条件
	 * @return
	 */
	public <X> X sum(final String propertyName, final Criterion... criterions);
	
	/**
	 * 返回指定属性的平均值
	 * 
	 * @param <X>
	 * @param propertyName 要求求平均值的属性名称
	 * @param criterions 限定条件
	 * @return
	 */
	public <X> X avg(final String propertyName, final Criterion... criterions);
	
	/**
	 * 返回指定属性的最大值
	 * 
	 * @param <X>
	 * @param propertyName 要求求最大值的属性名称
	 * @param criterions 限定条件
	 * @return
	 */
	public <X> X max(final String propertyName, final Criterion... criterions);
	
	/**
	 * 返回指定属性的最小值
	 * 
	 * @param <X>
	 * @param propertyName 要求求最小值的属性名称
	 * @param criterions 限定条件
	 * @return
	 */
	public <X> X min(final String propertyName, final Criterion... criterions);
	
	/**
	 * 返回对象的记录总算
	 * 
	 * @param criterions 限定条件
	 * @return
	 */
	public long count(final Criterion... criterions);

	/**
	 * 执行定义在&lt;sql-query&gt;或&lt;query&gt;中的命名查询,包括定义在数据库中的存储过程或函数.
	 * 如果是定义在&lt;sql-query&gt;中的Function，必须返回一个结果集，如果是Proceduer，第一个参数必须是
	 * Out，它返回一个结果集,其余的Out参数将被忽略.
	 * 
	 * @param <X>
	 * @param queryName 定义在&lt;sql-query&gt;或&lt;query&gt;中的命名查询，包括数据库中的存储过程或函数
	 * @param values 可变类型参数
	 * @return
	 */
	public <X> List<X> findByNamedQuery(final String queryName, final Object... values);

	/**
	 * 执行定义在&lt;sql-query&gt;或&lt;query&gt;中的命名查询,不包括定义在数据库中的存储过程或函数
	 * 
	 * @param <X>
	 * @param queryName 定义在&lt;sql-query&gt;或&lt;query&gt;中的命名查询，不包括数据库中的存储过程或函数
	 * @param page
	 * @param values 可变类型参数
	 * @return
	 */
	public <X> List<X> findByNamedQuery(final String queryName, Page page, final Object... values);
	
	/**
	 * 执行定义在&lt;sql-query&gt;或&lt;query&gt;中的命名查询,包括定义在数据库中的存储过程或函数.
	 * 如果是定义在&lt;sql-query&gt;中的Function，必须返回一个结果集，如果是Proceduer，第一个参数必须是
	 * Out，它返回一个结果集,其余的Out参数将被忽略.
	 * 
	 * @param <X>
	 * @param queryName 定义在&lt;sql-query&gt;或&lt;query&gt;中的命名查询，包括数据库中的存储过程或函数
	 * @param values 命名参数
	 * @return
	 */
	public <X> List<X> findByNamedQuery(final String queryName, final Map<String, ?> values);
	
	/**
	 * 执行定义在&lt;sql-query&gt;或&lt;query&gt;中的命名查询,不包括定义在数据库中的存储过程或函数
	 *
	 * @param <X>
	 * @param queryName 定义在&lt;sql-query&gt;或&lt;query&gt;中的命名查询，不包括数据库中的存储过程或函数
	 * @param page
	 * @param values 命名参数
	 * @return
	 */
	public <X> List<X> findByNamedQuery(final String queryName, Page page, final Map<String, ?> values);

	/**
	 * 执行定义在&lt;sql-query&gt;或&lt;query&gt;中的update或delete命名查询,包括定义在数据库中的存储过程或函数.
	 * 
	 * @param queryName 定义在&lt;sql-query&gt;或&lt;query&gt;中的update或delete命名查询，包括数据库中的存储过程或函数
	 * @param values 可变类型参数
	 * @return
	 */
	public int executeNamedQuery(String queryName, Object... values);

	/**
	 * 执行一个update或者delete的native sql
	 * 
	 * @param nativeSql String
	 * @return int 执行的sql影响到的记录数.
	 */
	public int executeSqlUpdate(final String nativeSql, final Object... values);
	
	/**
	 * 执行一个select的native sql
	 * 
	 * @param <X> Object[]
	 * @param nativeSql
	 * @param values 参数按顺序绑定
	 * @return
	 */
	public <X> List<X> executeSql(final String nativeSql, final Object... values);
	
	/**
	 * 执行一个select的native sql，返回List类型为当前model类型
	 * 
	 * @param nativeSql
	 * @param values
	 * @return
	 */
	public List<T> executeSqlModel(final String nativeSql, final Object... values);
	
	/**
	 * 执行一个select的native sql
	 * 
	 * @param nativeSql
	 * @param values  参数按顺序绑定
	 * @return
	 */
	@SuppressWarnings("rawtypes")
	public List<Map> executeSqlMap(final String nativeSql, final Object[] values);
	
	/**
	 * 分页执行一个select的native sql.
	 * 
	 * @param page 分页对象
	 * @param nativeSql sql语句
	 * @param values 参数按顺序绑定
	 * @return
	 */
	@SuppressWarnings("rawtypes")
	public List<Map> executeSqlMap(Page page, final String nativeSql, final Object[] values);

	/**
	 * 执行HQL进行修改/删除操作.
	 * 
	 * @param values 数量可变的参数,按顺序绑定.
	 * @return 更新记录数.
	 */
	public int execute(final String hql, final Object... values);

	/**
	 * 执行HQL进行修改/删除操作.
	 * 
	 * @param values 命名参数,按名称绑定.
	 * @return 更新记录数.
	 */
	public int execute(final String hql, final Map<String, ?> values);

	/**
	 * 判断对象的属性值在数据库内是否唯一.
	 * 
	 * 在修改对象的情景下,如果属性新修改的值(value)等于属性原来的值(orgValue)则不作比较.
	 */
	public boolean isPropertyUnique(final String propertyName, final Object newValue, final Object oldValue);

	/**
	 * 取得sequence的下一个值，此方法仅供Oracle DB使用.
	 * 
	 * @param sequenceName sequence名称
	 * @return
	 */
	public BigDecimal getSeqNextValue(String sequenceName);
}